lock если объект монитора уже закрыт просто блокирует поток
lock(obj){
...
}
Эта конструкция превращается в правую конструкцию
try{
var lockTaken = false;
Monitor.Enter(obj, ref lockTaken);
...
}
finally
{
if(lockTaken)
{
Monitor.Exit(obj)
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void CriticalMethod()
{
...
}
Он требуется чтобы пореже переключать контекст, т.к. в случае обычного лока, контекст переключается постоянно
private SpinLock obj = new SpinLock();
public void Method(){
var lockTaken = false;
try
{
obj.Enter(ref lockTaken);
}
finally
{
if(lockTaken){
obj.Exit(false);
}
}
}
Эта штука не перключает сразу контекст а запускает в цикле метод SpinOnce, в нем есть три варинта
SpinLock это структура, поэтому его нужно передавать строко по ref, иначе он будет не иметь смысла
Контекст потока — это всё состояние, необходимое процессору, чтобы приостановить выполнение потока и потом продолжить его с того же места.
Он включает:
Компонент | Что это такое |
---|---|
📌 Регистр EIP / RIP |
Адрес следующей инструкции (точка исполнения) |
📌 Стек ESP / RSP |
Указатель на вершину стека |
📦 Регистры общего назначения | eax , ebx , rcx , rdx и др. |
🧾 Флаги процессора | Режимы исполнения, флаги прерываний |
🗂️ Состояние SIMD/FPU (если нужно) | Для векторных операций, xmm , ymm |
📎 Локальные переменные | Хранятся в стеке (или регистрах) |
🧩 Информация ОС | Приоритет, дескрипторы, права, область памяти |
Процесс переключения контекста, это когда ОС сохраняет текущее состояние контекста и загружает в процессор другой поток с другим контекстом.
Данная штука позволяет область кода сделать такой, чтобы все кто хотели могли читать, но писать мог только один и при этом, если кто то начинает писать, то все ребята на чтение заканчивают читать а все попытке прочесть становятся в очередь пока не закончиться запись
Существуют примитивы с приставкой Slim и без, отличие в том, что без такого суффикса примитивы появились раньше, когда дотнет был только под винду и они отличаются тем что опускали примитивы на уровень ОС, в то время как Slim разбираются на уровне приложения
Есть два вида потоко безопасных коллекций:
CuncurrentBag
CuncurrentStack
CuncurrentQueue
ConcurrentDictionary<TKey, TValue>
Добавляя новый элемент, поток добавляет каждый в свою коллекцию, а если читать, то сначала из своего, а потом блокировать другой поток и читать из чужого
ImmutableList
ImmutableArray
ImmutableHashSet
ImmutableQueue
ImmutableStack